package log;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import shared.Friend;
import shared.Pair;
import shared.PersonList;
import visualization.CreateGraph;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

import database.DatabaseClient;

public class Statistics 
{
	private Document document;
	private Integer peopleCount;
	private PersonList<Friend> friends;
	
	public Statistics(PersonList<Friend> personlist)
	{
		 document = new Document();
		 friends = personlist;
	     try 
	     {
			PdfWriter.getInstance(document,new FileOutputStream("statistics.pdf"));
		 } 
	     catch (FileNotFoundException e) 
	     {
	    	Log.console(e.getMessage());
		 } 
	     catch (DocumentException e) 
		 {
			Log.console(e.getMessage());
		 }	      
	}
	
	public void generateStatistics()
	{
		openFile();
		peopleCount = Integer.valueOf(countPeople());
		writeln("Liczba osob na grafie / calkowita ilosc w bazie: "+CreateGraph.get().getNodes().size()+"/"+peopleCount );		
		writeln("Liczba znajomosci na grafie / calkowita ilosc w bazie: "+CreateGraph.get().getEdges().size()+"/"+countFriendships());
		write("Statystyki plci [ilosc/procent]: ");
		generateGender();
		writeln("");
		write("Top 5 w ilosci przyjaciol: ");
		generateTop5Friends();		
		writeln("");
		write("Top 5 miast [ilosc osob/procent]: ");
		generateTop5Cities();
		writeln("");
		write("Struktura wieku[przedzial/ilosc/procent]: ");
		generateAgeStats();
		closeAndSave();
	}
	
	private void generateAgeStats()
	{				
		List <Pair<String,Integer>> agepairs = new ArrayList<Pair<String,Integer>>();
		agepairs.add(new Pair<String,Integer>("NULL",0));		//0
		agepairs.add(new Pair<String,Integer>("0-9",0));		//1
		agepairs.add(new Pair<String,Integer>("10-14",0));		//2
		agepairs.add(new Pair<String,Integer>("15-18",0));		//3
		agepairs.add(new Pair<String,Integer>("19-23",0));		//4
		agepairs.add(new Pair<String,Integer>("24-30",0));		//5
		agepairs.add(new Pair<String,Integer>("31-40",0));		//6
		agepairs.add(new Pair<String,Integer>("41-50",0));		//7
		agepairs.add(new Pair<String,Integer>("51+",0));		//8
		for(Friend f : friends)
		{
			int age = Integer.valueOf(f.getAge());
			if(age == 0)
				agepairs.get(0).setValue(agepairs.get(0).getValue()+1);
			if(age <= 9 && age > 0)
				agepairs.get(1).setValue(agepairs.get(1).getValue()+1);
			else if(age <= 14 && age > 9)
				agepairs.get(2).setValue(agepairs.get(2).getValue()+1);
			else if(age <= 15 && age > 14)
				agepairs.get(3).setValue(agepairs.get(3).getValue()+1);
			else if(age <= 19 && age > 18)
				agepairs.get(4).setValue(agepairs.get(4).getValue()+1);
			else if(age <= 24 && age > 23)
				agepairs.get(5).setValue(agepairs.get(5).getValue()+1);
			else if(age <= 31 && age > 30)
				agepairs.get(6).setValue(agepairs.get(6).getValue()+1);
			else if(age <= 41 && age > 50)
				agepairs.get(7).setValue(agepairs.get(7).getValue()+1);
			else if(age > 51)
				agepairs.get(8).setValue(agepairs.get(8).getValue()+1);				
		}	
		for(Pair<String,Integer> pair : agepairs)
			write(pair.getKey()+"  "+pair.getValue()+"  "+
		new BigDecimal(100*Double.valueOf(pair.getValue()/(double)friends.size())).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()+"%");
	}

	private void generateTop5Cities() 
	{		
		List <Pair<String,Integer>> citiespairs = new ArrayList<Pair<String,Integer>>();
		boolean isFound = false;
		double sum = 0;
		for(Friend f : friends)
		{
			isFound = false;
			for(Pair<String,Integer> pair : citiespairs)
				if(pair.getKey().equals(f.getCurrentplace()))
				{
					isFound = true; // duplicate found
					pair.setValue(pair.getValue()+1);
					break;			// break local for
				}
			if(isFound == true) 
				continue;			// continue global for
			citiespairs.add(new Pair<String,Integer>(f.getCurrentplace(),1));	
		}	
		sortPairs(citiespairs);
		citiespairs = citiespairs.subList(0, 5);
		for(Pair<String,Integer> pair : citiespairs)
			sum += pair.getValue();
		for(Pair<String,Integer> pair : citiespairs)
			write(pair.getKey()+" "+pair.getValue()+" "+
		new BigDecimal(100*Double.valueOf(pair.getValue()/sum)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()+"%");
	}	

	private void generateGender() 
	{		
		List <Pair<String,Integer>> genderpairs = new ArrayList<Pair<String,Integer>>();
		boolean isFound = false;
		double sum = 0;
		for(Friend f : friends)
		{
			isFound = false;
			for(Pair<String,Integer> pair : genderpairs)
				if(pair.getKey().equals(f.getGender()))
				{
					isFound = true; // duplicate found
					pair.setValue(pair.getValue()+1);
					break;			// break local for
				}
			if(isFound == true) 
				continue;			// continue global for
			genderpairs.add(new Pair<String,Integer>(f.getGender(),1));			
		}	
		for(Pair<String,Integer> pair : genderpairs)
			sum += pair.getValue();
		for(Pair<String,Integer> pair : genderpairs)
			write(pair.getKey()+" "+pair.getValue()+" "+
		new BigDecimal(100*Double.valueOf(pair.getValue()/sum)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()+"%");
	}

	private void generateTop5Friends()
	{
		DatabaseClient dbc = new DatabaseClient();
		dbc.connect();
		ResultSet rs = dbc.executeQuery("select TOP 5 friendName, friendSurname, count(friendIdA) " +
				"from friendship, friend	where FRIENDSHIP.friendIdA=FRIEND.friendId group by friendName, " +
				"friendSurname order by count(friendIdA) desc");		
		try 
		{
			while(rs.next())
				write(rs.getString("friendName")+" "+rs.getString("friendSurname")+" "+rs.getString(3));
		} 
		catch (SQLException e) 
		{		
			Log.console(e.getMessage());
		}
		dbc.disconnect();
	}
	
	private String countFriendships()
	{
		DatabaseClient dbc = new DatabaseClient();
		dbc.connect();
		ResultSet rs = dbc.executeQuery("select count(friendIdA) from friendship");
		try 
		{
			if(rs.next())
			{
				String x = rs.getString(1);
				dbc.disconnect();
				return x;
			}
		} 
		catch (SQLException e) 
		{		
			Log.console(e.getMessage());
		}
		dbc.disconnect();
		return "0";
	}
	
	private String countPeople()
	{
		DatabaseClient dbc = new DatabaseClient();
		dbc.connect();
		ResultSet rs = dbc.executeQuery("select count(friendId) from friend");
		try 
		{
			if(rs.next())
			{
				String x = rs.getString(1);
				dbc.disconnect();
				return x;
			}
		} 
		catch (SQLException e) 
		{		
			Log.console(e.getMessage());
		}
		dbc.disconnect();
		return "0";
	}
	
	private void openFile()
	{
		document.open();  
	}
	
	private void closeAndSave()
	{
		document.close(); 
	}
	
	private <T> void write(T message)
	{
		 try
		 {
			document.add(new Paragraph(String.valueOf(message)));		
		 } 
		 catch (DocumentException e) 
		 {
			Log.console(e.getMessage());
		 }
	}
	
	private <T> void writeln(T message)
	{
		 try
		 {
			document.add(new Paragraph(String.valueOf(message)));		
			document.add(new Paragraph(" "));
		 } 
		 catch (DocumentException e) 
		 {
			Log.console(e.getMessage());
		 }
	}
	
	private void sortPairs(List<Pair<String,Integer>> pairs)
	{
		int n = pairs.size();
		int i, j;
		Pair<String,Integer> t;
		  for(i = 0; i < n; i++)
		  {
			  for(j = 1; j < (n-i); j++)
			  {
				  if(pairs.get(j-1).getValue() < pairs.get(j).getValue())
				  {
				  t = pairs.get(j-1);
				  pairs.set(j-1, pairs.get(j));
				  pairs.set(j, t);
				  }
			  }
		  }
	} 
}
